<?php
/**
 * Talents come from diligence, and knowledge is gained by accumulation.
 *
 * @author: 晋<657306123@qq.com>
 */

namespace Xin\Filesystem\Adapter;

/**
 * Class CacheFileInfoPool
 */
class CacheFileInfoPool implements \ArrayAccess, \Countable, \IteratorAggregate{

	/**
	 * @var int
	 */
	protected $max = 100;

	/**
	 * @var array
	 */
	protected $data = [];

	/**
	 * @var int
	 */
	protected $count = 0;

	/**
	 * CacheFileInfoPool constructor.
	 *
	 * @param int $max
	 */
	public function __construct($max = 100){
		$this->max = $max;
	}

	/**
	 * @param string $key
	 * @param mixed  $info
	 */
	public function put($key, $info){
		$cacheKey = $this->resolveKey($key);
		if(isset($this->data[$cacheKey])){
			return;
		}

		$this->resolveOverflow();

		$this->data[$cacheKey] = $info;
		$this->count++;
	}

	/**
	 * @param string   $key
	 * @param callable $callback
	 * @return mixed|null
	 */
	public function get($key, $callback = null){
		$cacheKey = $this->resolveKey($key);
		$info = isset($this->data[$cacheKey]) ? $this->data[$cacheKey] : null;

		if(is_callable($callback) && !$info){
			$info = call_user_func($callback, $key);
			if($info){
				$this->put($key, $info);
			}
		}

		return $info;
	}

	/**
	 * @param string $key
	 */
	public function delete($key){
		$cacheKey = $this->resolveKey($key);

		if(!isset($this->data[$cacheKey])){
			return;
		}
		unset($this->data[$cacheKey]);

		$this->count--;
	}

	/**
	 * @param string $key
	 * @return bool
	 */
	public function has($key){
		$cacheKey = $this->resolveKey($key);
		return isset($this->data[$cacheKey]);
	}

	/**
	 * @param string $key
	 * @return string
	 */
	protected function resolveKey($key){
		return md5($key);
	}

	/**
	 * 处理溢出
	 */
	protected function resolveOverflow(){
		if(!$this->isOverflow()){
			return;
		}

		$this->overflow();
	}

	/**
	 * 处理溢出的情况
	 *
	 * @param int $count
	 */
	protected function overflow($count = 1){
		for($i = 0; $i < $count; $i++){
			$key = key($this->data);
			if(!$key){
				break;
			}

			unset($this->data[$key]);
			$this->count--;
		}
	}

	/**
	 * 数据是否溢出
	 *
	 * @return bool
	 */
	protected function isOverflow(){
		return $this->count() >= $this->max;
	}

	/**
	 * @return int
	 */
	public function getMax(){
		return $this->max;
	}

	/**
	 * @param int $max
	 */
	public function setMax($max){
		$this->max = $max;
	}

	/**
	 * @return array
	 */
	public function getData(){
		return $this->data;
	}

	/**
	 * @return int
	 */
	public function count(){
		return $this->count;
	}

	/**
	 * @param string $offset
	 * @return bool
	 */
	public function offsetExists($offset){
		return $this->has($offset);
	}

	/**
	 * @param string $offset
	 * @return mixed
	 */
	public function offsetGet($offset){
		return $this->get($offset);
	}

	/**
	 * @param string $offset
	 * @param mixed  $value
	 */
	public function offsetSet($offset, $value){
		$this->put($offset, $value);
	}

	/**
	 * @param string $offset
	 */
	public function offsetUnset($offset){
		$this->delete($offset);
	}

	/**
	 * @return \ArrayIterator|\Traversable
	 */
	public function getIterator(){
		return new \ArrayIterator($this->data);
	}

}
